package xyz.ziduo.lapcounter.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;

import java.util.ArrayList;

import xyz.ziduo.lapcounter.MainActivity;

public class WaveformView extends View {
    private static String TAG = "LC: " + WaveformView.class.getSimpleName();

    public enum ModeType {Mode_1_Waveform, Mode_3_Waveform};
    private ModeType modeType; // 绘图模式
    private final float paddSE = 30; // 左右内边距
    private final float paddTB = 30; // 上下内边距
    private float mWidth, mHeight; // 视图宽高
    private float widthUse, heightUse; // 绘图实际使用的长宽，即宽高-内边距
    private MainActivity.RunData runDataMode_3_Waveform_All; // 1波形模式使用的跑步数据
    // 3波形模式使用的3个跑步数据
    private MainActivity.RunData runDataMode_3_Waveform_Worst;
    private MainActivity.RunData runDataMode_3_Waveform_Best;
    private MainActivity.RunData runDataMode_3_Waveform_Most_Recent;
    private int colorMode_1_Waveform_All; // 1波形模式的波形颜色
    private int colorMode_3_Waveform_Worst; // 3波形模式的波形颜色
    private int colorMode_3_Waveform_Best; // 3波形模式的波形颜色
    private int colorMode_3_Waveform_Most_Recent; // 3波形模式的波形颜色
    private Paint mPaint;
    private Path mPath;
    private final int mStrokeWidth = 3; // 波形图线条宽度

    public WaveformView(Context context) {
        super(context);
    }

    public WaveformView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public WaveformView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(modeType == null) return;
        // 计算基础数据
        if(!countBaseValue()) {
            // 清空画布
            canvas.drawColor(Color.TRANSPARENT);
            return;
        }
        switch (modeType) {
            case Mode_1_Waveform:
                if(runDataMode_3_Waveform_All == null) return;
                doDraw(canvas, runDataMode_3_Waveform_All, colorMode_1_Waveform_All);
                break;
            case Mode_3_Waveform: // 三个源数据按 最差 最好 最近 顺序绘制
                switch (waveform3Flag) {
                    case 0: // 全不显示
                        break;
                    case 1: // worst 显示
                        doDraw(canvas, runDataMode_3_Waveform_Worst, colorMode_3_Waveform_Worst);
                        break;
                    case 2: // best 显示
                        doDraw(canvas, runDataMode_3_Waveform_Best, colorMode_3_Waveform_Best);
                        break;
                    case 3: // worst best 显示
                        doDraw(canvas, runDataMode_3_Waveform_Worst, colorMode_3_Waveform_Worst);
                        doDraw(canvas, runDataMode_3_Waveform_Best, colorMode_3_Waveform_Best);
                        break;
                    case 4: // most_recent 显示
                        doDraw(canvas, runDataMode_3_Waveform_Most_Recent, colorMode_3_Waveform_Most_Recent);
                        return;
                    case 5: // worst most_recent 显示
                        doDraw(canvas, runDataMode_3_Waveform_Worst, colorMode_3_Waveform_Worst);
                        doDraw(canvas, runDataMode_3_Waveform_Most_Recent, colorMode_3_Waveform_Most_Recent);
                        break;
                    case 6: // best most_recent 显示
                        doDraw(canvas, runDataMode_3_Waveform_Best, colorMode_3_Waveform_Best);
                        doDraw(canvas, runDataMode_3_Waveform_Most_Recent, colorMode_3_Waveform_Most_Recent);
                        break;
                    case 7: // worst best most_recent 显示
                        doDraw(canvas, runDataMode_3_Waveform_Worst, colorMode_3_Waveform_Worst);
                        doDraw(canvas, runDataMode_3_Waveform_Best, colorMode_3_Waveform_Best);
                        doDraw(canvas, runDataMode_3_Waveform_Most_Recent, colorMode_3_Waveform_Most_Recent);
                        break;
                }
                break;
        }
    }

    // 已加载后的初始化
    // mode：Mode_3_Waveform 表示三波线模式，Mode_1_Waveform 表示一波线模式
    public void init(ModeType mode, int width, int height, int colorMode_1_Waveform_All,
                     int colorMode_3_Waveform_Worst, int colorMode_3_Waveform_Best, int colorMode_3_Waveform_Most_Recent) {
        this.modeType = mode;
        mWidth = width;
        mHeight = height;
        widthUse = mWidth - 2 * paddSE;
        heightUse = mHeight - 2 * paddTB;
        this.colorMode_1_Waveform_All = colorMode_1_Waveform_All;
        this.colorMode_3_Waveform_Worst = colorMode_3_Waveform_Worst;
        this.colorMode_3_Waveform_Best = colorMode_3_Waveform_Best;
        this.colorMode_3_Waveform_Most_Recent = colorMode_3_Waveform_Most_Recent;

        // 画笔和路径
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPath = new Path();
    }

    // 1波形模式下更新UI
    // 参数为波形的数据源
    public void updateUIMode_1_Waveform(MainActivity.RunData allRunData) {
        runDataMode_3_Waveform_All = allRunData;
        this.invalidate();
    }

    private int waveform3Flag;
    // 3波形模式下更新UI
    // 参数为3个波形的数据源，分别对应 最差 最好 最近
    // flag为标志位，用于标识源数据是否为null，runData1-3分别为0-2位；当置位为0时表示该源数据为null，即不绘制
    public void updateUIMode_3_Waveform(MainActivity.RunData worstRunData,
                                        MainActivity.RunData bestRunData,
                                        MainActivity.RunData mostRecentRunData, int flag) {
        runDataMode_3_Waveform_Worst = worstRunData;
        runDataMode_3_Waveform_Best = bestRunData;
        runDataMode_3_Waveform_Most_Recent = mostRecentRunData;
        this.waveform3Flag = flag;
        this.invalidate();
    }

    // 实际绘制函数
    // runData：数据源
    // lineColor：波线颜色
    // 注意：当 yUnitPxPerVal<0 时表示数据无波动，因除数不能为0，所以无法绘制
    private void doDraw(Canvas canvas, MainActivity.RunData runData, int lineColor) {
        // 路径重置
        mPath.reset();

        // 画笔初始化
        mPaint.setAlpha(255);
        mPaint.setColor(lineColor);
        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setStyle(Paint.Style.FILL);
        // 进行绘制
        // 波线的x坐标计算公式：左右内边距 + (点索引 * x轴单位)
        // 波线的y坐标计算公式：(配速值 - y轴原点对应值) * y轴单位
        ArrayList<Double> paceList = runData.paceList;
        float x = paddSE;
        float y = (float) ( (paceList.get(0) - y0Val) * yUnitPxPerVal );
        canvas.drawCircle(x, y, mStrokeWidth, mPaint);

        mPath.moveTo(x, y);
        for (int i = 1; i < paceList.size(); ++i) {
            x = paddSE + i * xUnitPxPerVal;
            y = (float) ( (paceList.get(i) - y0Val) * yUnitPxPerVal );
            mPath.lineTo(x, y);
            canvas.drawCircle(x, y, mStrokeWidth, mPaint);
        }

        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(mPath, mPaint);
    }

    // 计算用于绘制的基础值
    private boolean countBaseValue() {
        switch (modeType) {
            case Mode_1_Waveform:
                return countBaseValue(runDataMode_3_Waveform_All);
            case Mode_3_Waveform:
                return countBaseValueMode_3_Wavefor();
            default:
                return false;
        }
    }

    // 计算绘制波线模式3时的基础值
    // 返回 true 表示可绘制，false 表示无法绘制
    // 注意：当波线无波动时，无法计算 yUnitPxPerVal，也就无法绘制
    private boolean countBaseValueMode_3_Wavefor() {
        Log.e(TAG, "flg: " + waveform3Flag);
        switch (waveform3Flag) {
            case 0: // 全不显示
                return false;
            case 1: // worst 显示
                return countBaseValue(runDataMode_3_Waveform_Worst);
            case 2: // best 显示
                return countBaseValue(runDataMode_3_Waveform_Best);
            case 3: // worst best 显示
                return countBaseValue(runDataMode_3_Waveform_Worst, runDataMode_3_Waveform_Best);
            case 4: // most_recent 显示
                return countBaseValue(runDataMode_3_Waveform_Most_Recent);
            case 5: // worst most_recent 显示
                return countBaseValue(runDataMode_3_Waveform_Worst, runDataMode_3_Waveform_Most_Recent);
            case 6: // best most_recent 显示
                return countBaseValue(runDataMode_3_Waveform_Best, runDataMode_3_Waveform_Most_Recent);
            case 7: // worst best most_recent 显示
                return countBaseValue(runDataMode_3_Waveform_Worst, runDataMode_3_Waveform_Best,
                        runDataMode_3_Waveform_Most_Recent);
            default:
                return false;
        }
    }

    // xUnitPxPerVal 波线的x轴单位计算公式：x实际使用宽度 / (跑步数据最大个数-1)
    // 波线的x坐标计算公式：左右内边距 + (点索引 * x轴单位)

    // yUnitPxPerVal 波线的y轴单位计算公式：y实际使用宽度 / (配速最大值 - 配速最小值)
    // y轴原点对应值的计算依据：平均值位于波形图中间位置
    // y0Val 波线的y轴原点对应值的计算公式： 配速最小值 - 上下内边距 / y轴单位
    // 波线的y坐标计算公式：(配速值 - y轴原点对应值) * y轴单位
    private float xUnitPxPerVal; // x轴的单位
    private float yUnitPxPerVal; // y轴的单位
    private float y0Val; // y轴原点对应的值
    // 计算基础数据，用于当数据源只有一个时
    // 返回值表示是否可绘制
    // 当数据没有波动时不能绘制
    private boolean countBaseValue(MainActivity.RunData runData) {
        int maxRunCount;
        double maxPace, minPace, maxP_minP;
        ArrayList<Double> paceList;
        if(runData == null) return false;
        maxRunCount = runData.paceList.size() - 1;
        xUnitPxPerVal = widthUse / maxRunCount; // 注意：除数不能为0，但源数据添加方式保证数据不会为空
        maxPace = 0;
        minPace = Integer.MAX_VALUE;
        paceList = runData.paceList;
        for(double pace : paceList) {
            if(maxPace < pace) maxPace = pace;
            if(minPace > pace) minPace = pace;
        }
        Log.e(TAG, String.format("max: %f, min: %f", maxPace, minPace));
        maxP_minP = (maxPace - minPace);
        if(maxP_minP == 0) return false; // 注意：除数不能为0，也就是说不能绘制无波动的数据
        yUnitPxPerVal = (float) ( heightUse / maxP_minP );
        y0Val = (float) ( minPace - paddTB / yUnitPxPerVal);
        return true;
    }

    // 计算基础数据，用于有两个数据源时
    // 返回值表示是否可绘制
    // 当数据没有波动时不能绘制
    private boolean countBaseValue(MainActivity.RunData runData1, MainActivity.RunData runData2) {
        int maxRunCount;
        double maxPace, minPace, maxP_minP;
        ArrayList<Double> paceList;
        if(runData1 == null || runData2 == null) return false;
        maxRunCount = Math.max(runData1.paceList.size(), runData2.paceList.size()) - 1;
        xUnitPxPerVal = widthUse / maxRunCount; // 注意：除数不能为0，但源数据添加方式保证数据不会为空
        maxPace = 0;
        minPace = Integer.MAX_VALUE;
        paceList = runData1.paceList;
        for(double pace : paceList) {
            if(maxPace < pace) maxPace = pace;
            if(minPace > pace) minPace = pace;
        }
        paceList = runData2.paceList;
        for(double pace : paceList) {
            if(maxPace < pace) maxPace = pace;
            if(minPace > pace) minPace = pace;
        }
        maxP_minP = (maxPace - minPace);
        if(maxP_minP == 0) return false; // 注意：除数不能为0，也就是说不能绘制无波动的数据
        yUnitPxPerVal = (float) ( heightUse / maxP_minP );
        y0Val = (float) ( minPace - paddTB / yUnitPxPerVal );
        return true;
    }

    // 计算基础数据，用于有三个数据源时
    // 返回值表示是否可绘制
    // 当数据没有波动时不能绘制
    private boolean countBaseValue(MainActivity.RunData runData1, MainActivity.RunData runData2,
                                   MainActivity.RunData runData3) {
        int maxRunCount;
        double maxPace, minPace, maxP_minP;
        ArrayList<Double> paceList;
        if(runData1 == null || runData2 == null || runData3 == null) return false;
        maxRunCount = Math.max(runData1.paceList.size(), runData2.paceList.size());
        maxRunCount = Math.max(maxRunCount, runData3.paceList.size()) - 1;
        xUnitPxPerVal = widthUse / maxRunCount; // 注意：除数不能为0，但源数据添加方式保证数据不会为空
        maxPace = 0;
        minPace = Integer.MAX_VALUE;
        paceList = runData1.paceList;
        for(double pace : paceList) {
            if(maxPace < pace) maxPace = pace;
            if(minPace > pace) minPace = pace;
        }
        paceList = runData2.paceList;
        for(double pace : paceList) {
            if(maxPace < pace) maxPace = pace;
            if(minPace > pace) minPace = pace;
        }
        paceList = runData3.paceList;
        for(double pace : paceList) {
            if(maxPace < pace) maxPace = pace;
            if(minPace > pace) minPace = pace;
        }
        maxP_minP = (maxPace - minPace);
        if(maxP_minP == 0) return false; // 注意：除数不能为0，也就是说不能绘制无波动的数据
        yUnitPxPerVal = (float) ( heightUse / maxP_minP );
        y0Val = (float) ( minPace - paddTB / yUnitPxPerVal );
        return true;
    }
}
